#include "MysqlPreparedStatement.h"
#include "exception/SQLException.h"

using namespace std;
using namespace mysql;

MysqlPreparedStatement::MysqlPreparedStatement(MYSQL *conn, const string &sql) :
        conn_(conn), stmt_(mysql_stmt_init(conn)) {
    if (!stmt_) {
        throw SQLException("Could not initialize statement", mysql_errno(conn), mysql_error(conn));
    }
    if (mysql_stmt_prepare(stmt_, sql.c_str(), sql.size())) {
        throw SQLException("Query preparation failed", mysql_stmt_errno(stmt_), mysql_stmt_error(stmt_));
    }
    bind_.resize(mysql_stmt_param_count(stmt_));
}

void MysqlPreparedStatement::setInt(int parameter, int &value) {
    if (parameter < 1 || parameter > static_cast<int>(bind_.size())) {
        throw SQLException("Parameter index out of range", 0);
    }
    bind_[parameter - 1].buffer_type = MYSQL_TYPE_LONG;
    bind_[parameter - 1].buffer = (char *) &value;
}

void MysqlPreparedStatement::setString(int parameter, const std::string &value) {
    if (parameter < 1 || parameter > static_cast<int>(bind_.size())) {
        throw SQLException("Parameter index out of range", 0);
    }
    bind_[parameter - 1].buffer_type = MYSQL_TYPE_STRING;
    bind_[parameter - 1].buffer = (char *) &value[0];
    bind_[parameter - 1].buffer_length = value.size();
}

void MysqlPreparedStatement::bindParameters() {
    if (mysql_stmt_bind_param(stmt_, bind_.data())) {
        throw SQLException("Binding parameter failed", mysql_stmt_errno(stmt_), mysql_stmt_error(stmt_));
    }
}

bool MysqlPreparedStatement::execute() {
    bindParameters();
    if (mysql_stmt_execute(stmt_)) {
        throw SQLException("Query execution failed", mysql_stmt_errno(stmt_), mysql_stmt_error(stmt_));
    }
    return true;
}

MysqlResult MysqlPreparedStatement::executeQuery() {
    execute();
    return MysqlResult(stmt_);
}
